package com.echat.serviceapigateway.security.service.impl;

import com.echat.commonlib.exception.exc.BussinessException;
import com.echat.commonlib.exception.exc.ValidateFailedException;
import com.echat.commonlib.util.SpringContextUtil;
import com.echat.serviceapigateway.security.config.CacheConfig;
import com.echat.serviceapigateway.security.mapper.ResourceMapper;
import com.echat.serviceapigateway.security.model.authorization.Resource;
import com.echat.serviceapigateway.security.model.authorization.vo.PermissionNode;
import com.echat.serviceapigateway.security.model.authorization.vo.ResourceVo;
import com.echat.serviceapigateway.security.service.AuthorizationService;
import com.echat.serviceapigateway.security.service.ResourceService;
import com.echat.serviceapigateway.security.service.ServiceService;
import com.echat.serviceapigateway.security.tool.StringUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by chenmohan on 2018/09/17
 *
 * @description
 */
@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    ResourceMapper resourceMapper;

    @Autowired
    ServiceService serviceService;

    @Autowired
    AuthorizationService authorizationService;

    @Override
    public List<Resource> listAll() {
        List<Resource> resourceList = resourceMapper.selectAll();
        return resourceList;
    }

    @Cacheable(value = CacheConfig.CACHE_USER_AUTH_TREE, key = "#userId")
    @Override
    public List<PermissionNode> getAuthTree(Long userId) {
        List<Resource> allResources = resourceMapper.selectAll();
        Map<String, Resource> userResourceMap = authorizationService.listResourcesByUserId(userId)
                .parallelStream().collect(Collectors.toMap(e -> e.getUri(), e -> e));

        List<Resource> serviceResourceList = serviceService.listAll().stream()
                .map(e -> Resource.builder()
                        .serviceId(e.getId())
                        .memo(e.getMemo())
                        .uri(e.getServiceUri()).build())
                .collect(Collectors.toList());

        List<PermissionNode> nodeList = serviceResourceList.stream().map(e -> {
            Boolean[] serviceNodeChecked = {new Boolean(false)};
            PermissionNode serviceNode = PermissionNode.builder()
                    .name(e.getMemo())
                    .value(e.getId())
                    .list(allResources.stream()
                            .filter(r -> e.getUri().equals(r.serviceUri()))
                            .map(r -> {
                                PermissionNode node = PermissionNode.builder()
                                        .name(r.getMemo())
                                        .value(r.getId()).build();
                                if (userResourceMap != null && userResourceMap.get(r.getUri()) != null) {
                                    node.setChecked(true);
                                    serviceNodeChecked[0] = true;
                                }
                                return node;
                            })
                            .collect(Collectors.toList())).build();
            if (serviceNodeChecked[0]) {
                serviceNode.setChecked(true);
            }
            return serviceNode;
        }).collect(Collectors.toList());
        return nodeList;
    }

    @Override
    public List<Resource> listByIds(List<Long> ids) {
        if (ids == null || ids.size() == 0) {
            return Collections.EMPTY_LIST;
        }
        Example example = new Example(Resource.class);
        example.createCriteria().andIn("id", ids);
        List<Resource> resourceList = resourceMapper.selectByExample(example);
        return resourceList;
    }


    @Cacheable(value = CacheConfig.CACHE_RESOURCE, key = "#uri")
    @Override
    public Resource getByResourceUri(String uri) {
        Example example = new Example(Resource.class);
        example.createCriteria().andEqualTo("uri", uri);
        Resource resource = resourceMapper.selectOneByExample(example);
        return resource;
    }

    @Override
    public ResourceVo getVoById(Long id) {
        if (id == null) {
            throw new BussinessException("id 不能为空");
        }
        ResourceVo vo = resourceMapper.selectResourceVosById(id);
        return vo;
    }

    @Override
    public PageInfo<ResourceVo> listVoByCondition(Resource condition) {
        if (condition == null) {
            throw new BussinessException("listVoByCondition(Resource condition),condtition 不能为空");
        }
        PageHelper.startPage(condition.getPage(), condition.getLimit());
        List<ResourceVo> resourceVos = resourceMapper.selectResourceVosByCondition(condition);
        PageInfo<ResourceVo> resourceVoPageInfo = new PageInfo<>(resourceVos);
        return resourceVoPageInfo;
    }

    @Override
    public Resource update(Resource resource) {
        if (resource.getId() == null) {
            throw new ValidateFailedException("id 不能为空");
        }
        resourceMapper.updateByPrimaryKeySelective(resource);
        return resource;
    }

    @Override
    public Resource add(Resource resource) {
        com.echat.serviceapigateway.security.model.authorization.Service service = serviceService.getById(resource.getServiceId());
        if (service == null || StringUtils.isEmpty(resource.getUri())) {
            throw new ValidateFailedException("缺少必要参数!");
        }
        String uri = service.getServiceUri() + resource.getUri();
        //接口映射不能重复
        ResourceService exResourceService = (ResourceService) SpringContextUtil.getBean(this.getClass());
        if (exResourceService.getByResourceUri(uri) != null) {
            throw new BussinessException("接口地址已经存在，请重新填写");
        }
        //要拼接上Service的Uri,这样权限树那边才能够正确显示出新增的可配置权限
        resource.setUri(uri);
        LocalDateTime now = LocalDateTime.now();
        resource.setCreateTime(now);
        resource.setModifyTime(now);
        resourceMapper.insertSelective(resource);
        return resource;
    }

    @Override
    public Resource remove(Resource delete) {
        if (delete.getId() == null) {
            throw new ValidateFailedException("id 不能空");
        }
        resourceMapper.deleteByPrimaryKey(delete);
        return delete;
    }

}
